package com.cskaoyan.shiro;

import com.cskaoyan.bean.Admin;
import com.cskaoyan.bean.AdminExample;
import com.cskaoyan.mapper.AdminMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

@Component
public class CustomRealm extends AuthorizingRealm {

    @Autowired
    AdminMapper adminMapper;

    ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 提供认证信息
     * @param authenticationToken
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 参数AuthenticationToken 来源于 subject.login的时候携带的参数
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        // 从认证用户给的token是否正确（到DB中验证）
        String username = token.getUsername();

        //根据username查询到正确的密码 → 通常维护在数据库里
        AdminExample example = new AdminExample();
        example.createCriteria().andUsernameEqualTo(username);
        List<Admin> admins = adminMapper.selectByExample(example);
        if (admins == null || admins.size() == 0) {
            return null;    // 用户名不存在的情况，会认证失败
        }
        Admin admin = admins.get(0);
        String credential = admin.getPassword(); //数据库中维护的当前用户名的password

        //第一个参数：Principal 应用程序中维护的Principal信息，如果认证成功，会维护在session中
        //第二个参数：credentials 正确的凭据，用户的password需要和credentials一致，才能认证成功；认证失败会抛异常
        //第三个参数：realm的名称
        return new SimpleAuthenticationInfo(admin, credential, this.getName());
    }

    /**
     * 提供授权信息
     * @param principalCollection
     * @return
     */
    @SneakyThrows
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 1.获得用户信息principal → 上面返回认证信息的第一个参数里维护了用户信息
        Admin primaryPrincipal = (Admin) principalCollection.getPrimaryPrincipal();
        Integer id = primaryPrincipal.getId();

        // 2.根据用户信息获得他所有的权限信息 → DB中，admin表 -> role表 -> permission表
        // 2.1 role是个数组，应该先查出role id数组
        String roles = adminMapper.queryRolesArrByName(id);
        Integer[] roleArr = objectMapper.readValue(roles, Integer[].class);
        // 2.2 传入role id 数组 去perm表查perm
        List<String> permissions = null;
        if(roleArr.length > 0){
            List<Integer> roleIds = Arrays.asList(roleArr);
            permissions = adminMapper.queryPermsByRoleIds(roleIds);
        }

        // 3.给授权信息 增加上该用户所拥有的权限
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addStringPermissions(permissions);
        return simpleAuthorizationInfo;
    }


}
